#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Log.hpp"

using namespace std;
using namespace LogModule;

class Reactor // 基座  Reactor反应堆模式高并发网络服务器
{
    static const int size = 128;
private:
    bool IsAddConnectionHelper(int sockfd) // 判断_connections中是否存在connection
    {
        auto iter = _connections.find(sockfd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }
    bool IsAddConnectionExist(const shared_ptr<Connection> &conn)
    {
        return IsAddConnectionHelper(conn->GetSockFd());
    }
    bool IsAddConnectionExist(int sockfd)
    {
        return IsAddConnectionHelper(sockfd);
    }
    bool IsConnectionEmpty()    //判断_connections是否为空
    {
        return _connections.empty();
    }
    int LoopOnce(int timeout)
    {
        int n = _epoller_ptr->WaitEvents(_revs, size, timeout); // 获取就绪队列中的就绪事件
        return n;
    } 
    void Dispatcher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;     // 拿到就绪队列中就绪的文件描述符
            uint32_t events = _revs[i].events; // 拿到就绪队列中的事件
            if (events & EPOLLERR)             // 就绪事件这里不管出什么错都进EPOLLIN|EPOLLOUT让具体的异常处理进行处理
                events |= (EPOLLIN | EPOLLOUT);
            if (events & EPOLLHUP)
                events |= (EPOLLIN | EPOLLOUT);
            if (events & EPOLLIN)
            {
                // 读事件就绪
                if (IsAddConnectionExist(sockfd))
                    _connections[sockfd]->Recver();//索引_connection中connection对象
            }
            if (events & EPOLLOUT)
            {
                // 写事件就绪
                if (IsAddConnectionExist(sockfd))
                    _connections[sockfd]->Sender();
            }
        }
    }

public:
    Reactor()
        : _epoller_ptr(make_unique<Epoller>())
        ,_isrunning(false)
    {
        memset(_revs, 0, sizeof(_revs)); // 初始化 _revs
    }
    void Loop()
    {
        if (IsConnectionEmpty())
            return;
        _isrunning = true;
        int timeout=-1;
        while (_isrunning)
        {
            PrintConnection();
            int n=LoopOnce(timeout);    //获取就绪队列就绪事件个数
            Dispatcher(n);              //派发，读事件||写事件
        }
        _isrunning = false;
    }
    // 把所有新连接添加到_connections并把事件写到内核
    void AddConnection(shared_ptr<Connection> &conn)
    {
        if (IsAddConnectionExist(conn))
        {
            LOG(LogLevel::WARNING) << "connection is exist" << conn->GetSockFd();
            return;
        }
        uint32_t events = conn->GetEvent();     // 一个connection中的事件
        int sockfd = conn->GetSockFd();         // 一个connection中的文件描述符
        _epoller_ptr->AddEvent(sockfd, events); // 写入内核
        conn->SetOwner(this);                   //设置回指指针把reactor对象设置到connection基类
        _connections[sockfd] = conn;            //把connection放到_connections中
    }
    //关心写事件，关写事件的connection放进_connections中就又走那个派发逻辑了，然后再去发数据(妙！)
    void EnableReadWrite(int sockfd,bool enableread,bool enablewrit)
    {
        if(!IsAddConnectionExist(sockfd))
        {
            LOG(LogLevel::WARNING) << "connection is not exist" << sockfd;
            return;
        }
        uint32_t new_event=(EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrit ? EPOLLOUT : 0));
        _connections[sockfd]->SetEvent(new_event);

        _epoller_ptr->ModEvent(sockfd,new_event);
    }
    //异常处理(关闭文件描述符)
    void DelConnection(int sockfd) 
    {
        _epoller_ptr->DelEvent(sockfd);     //移除关心事件
        _connections.erase(sockfd);         //_connections移除自己
        close(sockfd);                      //关闭文件描述符
        LOG(LogLevel::DEBUG)<<"client quit";
    }
    void PrintConnection()
    {
        std::cout << "当前Reactor正在进行管理的fd List:";
        for(auto &conn : _connections)
        {
            std::cout << conn.second->GetSockFd() << " ";
        }
        std::cout << "\r\n";
    }
    ~Reactor()
    {
    }

private:
    unique_ptr<Epoller> _epoller_ptr;                        // 构造epoll模型
    unordered_map<int, shared_ptr<Connection>> _connections; // 管理每一个connection
    bool _isrunning;                                         // 判断是否启动
    struct epoll_event _revs[size];                          // 就绪队列就绪事件
};